image.png<template>
  <div class="role-management">
    <el-card class="role-list-card">
      <template #header>
        <div class="card-header">
          <div class="header-left">
            <!-- 添加角色按钮 -->
            <el-button type="primary" @click="showAddDialog = true">
              <el-icon>
                <Plus />
              </el-icon>
              添加角色
            </el-button>
          </div>
          <div class="header-right">
            <!-- 搜索输入框 -->
            <el-input v-model="searchKeyword" placeholder="搜索角色名称或描述" class="search-input"
              clearable @input="handleSearch" @clear="handleSearch">
              <template #prefix>
                <el-icon>
                  <Search />
                </el-icon>
              </template>
            </el-input>
            <!-- 状态过滤下拉框 -->
            <el-select v-model="statusFilter" placeholder="所有状态" class="status-select" @change="loadRoles">
              <el-option label="所有状态" value="" />
              <el-option label="启用" value="0" />
              <el-option label="禁用" value="2" />
            </el-select>
            <!-- 重置按钮 -->
            <el-button @click="resetFilters" type="default" class="reset-button">
              <el-icon>
                <Refresh />
              </el-icon>
              重置
            </el-button>
          </div>
        </div>
      </template>

      <!-- 角色列表表格 -->
      <div class="table-wrapper">
        <el-table :data="filteredRoles" class="centered-table" v-loading="loading" element-loading-text="加载中..." empty-text="暂无数据">
        <!-- 角色信息列：头像和角色名 -->
        <el-table-column label="角色信息" min-width="180" show-overflow-tooltip align="center" class-name="role-info-column">
          <template #default="{ row }">
            <div class="role-info">
              <!-- 角色头像 -->
              <el-avatar :size="40" :style="{ backgroundColor: getRoleColor(row.roleName) }">
                {{ row.roleName && row.roleName.charAt(0) }}
              </el-avatar>
              <div class="role-details">
                <div class="role-name">
                  <!-- 编辑模式下显示输入框，否则显示角色名 -->
                  <el-input v-if="editingRowId === row.id" v-model="row.roleName" placeholder="请输入角色名称" size="small" />
                  <el-tooltip v-else :content="row.roleName" placement="top">
                    <span class="role-name-text">{{ row.roleName }}</span>
                  </el-tooltip>
                </div>
              </div>
            </div>
          </template>
        </el-table-column>
        <!-- 角色描述列 -->
        <el-table-column prop="roleDescription" label="角色描述" min-width="250">
          <template #default="{ row }">
            <!-- 编辑模式下显示输入框 -->
            <div v-if="editingRowId === row.id">
              <el-input v-model="row.roleDescription" size="small" />
            </div>
            <div v-else>{{ row.roleDescription || '暂无描述' }}</div>
          </template>
        </el-table-column>
        <!-- 权限数量列 -->
        <el-table-column prop="permissionCount" label="权限数量" min-width="120" align="center">
          <template #default="{ row }">
            <el-tag type="info" size="small">
              {{ row.permissionCount || 0 }} 个权限
            </el-tag>
          </template>
        </el-table-column>
        <!-- 状态列 -->
        <el-table-column prop="status" label="状态" min-width="100" align="center">
          <template #default="{ row }">
            <!-- 编辑模式下显示切换按钮 -->
            <div v-if="editingRowId === row.id">
              <el-button 
                :type="row.status === '0' ? 'success' : 'danger'" 
                size="small" 
                @click="toggleRoleStatus(row)"
                style="width: 100%"
              >
                <el-icon v-if="row.status === '0'">
                  <Check />
                </el-icon>
                <el-icon v-else>
                  <Close />
                </el-icon>
                {{ row.status === '0' ? '启用中' : '禁用中' }}
              </el-button>
            </div>
            <!-- 非编辑模式下显示状态标签 -->
            <el-tag v-else :type="getStatusType(row.status || '')">
              {{ getStatusName(row.status || '') }}
            </el-tag>
          </template>
        </el-table-column>
        <!-- 创建时间列 -->
        <el-table-column prop="createdAt" label="创建时间" min-width="180" align="center">
          <template #default="{ row }">
            {{ formatDate(row.createdAt) }}
          </template>
        </el-table-column>
        <!-- 操作列 -->
        <el-table-column label="操作" min-width="280" fixed="right" align="center">
          <template #default="{ row }">
            <div class="operation-buttons">
              <!-- 查看角色详情按钮 -->
              <el-button type="text" size="small" @click="viewRole(row)">
                <el-icon>
                  <View />
                </el-icon>
              </el-button>
              <!-- 权限管理按钮 -->
              <el-button type="text" size="small" @click="managePermissions(row)" style="color: #409eff;">
                <el-icon>
                  <Setting />
                </el-icon>
                权限
              </el-button>
              <!-- 编辑模式下的操作按钮 -->
              <div v-if="editingRowId === row.id">
                <!-- 保存编辑按钮 -->
                <el-button type="text" size="small" @click="saveEdit(row.id)" style="color: #67c23a;">
                  <el-icon>
                    <Check />
                  </el-icon>
                </el-button>
                <!-- 取消编辑按钮 -->
                <el-button type="text" size="small" @click="cancelEdit" style="color: #f56c6c;">
                  <el-icon>
                    <Close />
                  </el-icon>
                </el-button>
              </div>
              <!-- 非编辑模式下的操作按钮 -->
              <div v-else>
                <!-- 开始编辑按钮 -->
                <el-button type="text" size="small" @click="openEdit(row.id)">
                  <el-icon>
                    <Edit />
                  </el-icon>
                </el-button>
                <!-- 删除角色按钮 -->
                <el-button type="text" size="small" @click="deleteRoleHandler(row)" style="color: #f56c6c;">
                  <el-icon>
                    <Delete />
                  </el-icon>
                </el-button>
              </div>
            </div>
          </template>
        </el-table-column>
        </el-table>
      </div>

      <!-- 分页组件 -->
      <div class="pagination-container">
        <el-pagination v-model:current-page="currentPage" v-model:page-size="pageSize" :page-sizes="[10, 20, 50, 100]"
          :total="total" layout="total, sizes, prev, pager, next, jumper" @size-change="handleSizeChange"
          @current-change="handleCurrentChange" />
      </div>
    </el-card>

    <!-- 添加角色对话框 -->
    <el-dialog v-model="showAddDialog" title="添加角色" width="500px">
      <el-form :model="roleForm" :rules="roleRules" ref="roleFormRef" label-width="100px">
        <!-- 角色名称字段 -->
        <el-form-item label="角色名称" prop="roleName">
          <el-input v-model="roleForm.roleName" />
        </el-form-item>
        <!-- 角色描述字段 -->
        <el-form-item label="角色描述" prop="roleDescription">
          <el-input v-model="roleForm.roleDescription" type="textarea" :rows="3" />
        </el-form-item>
      </el-form>
      <template #footer>
        <span class="dialog-footer">
          <el-button @click="showAddDialog = false">取消</el-button>
          <el-button type="primary" @click="addRoleHandler" :loading="addingRole">确定</el-button>
        </span>
      </template>
    </el-dialog>

    <!-- 角色详情对话框 -->
    <el-dialog v-model="showDetailDialog" title="角色详情" width="600px">
      <div class="role-detail">
        <!-- 角色详情头部：图标和基本信息 -->
        <div class="detail-header">
          <el-avatar :size="100" :style="{ backgroundColor: getRoleColor(selectedRoleDetail.roleName) }">
            {{ selectedRoleDetail.roleName && selectedRoleDetail.roleName.charAt(0) }}
          </el-avatar>
          <div class="detail-info">
            <h3>{{ selectedRoleDetail.roleName }}</h3>
            <div class="detail-meta">
              <!-- 角色描述 -->
              <span class="meta-item">
                <el-icon>
                  <Document />
                </el-icon>
                {{ selectedRoleDetail.roleDescription || '暂无描述' }}
              </span>
              <!-- 权限数量 -->
              <span class="meta-item">
                <el-icon>
                  <Setting />
                </el-icon>
                {{ selectedRoleDetail.permissionCount || 0 }} 个权限
              </span>
            </div>
          </div>
        </div>
        <el-divider />
        <!-- 角色详情内容 -->
        <div class="detail-content">
          <el-row :gutter="20">
            <!-- 左侧信息 -->
            <el-col :span="12">
       
              <!-- 状态信息 -->
              <div class="detail-item">
                <label>状态:</label>
                <el-tag :type="getStatusType(selectedRoleDetail.status || '')">
                  {{ getStatusName(selectedRoleDetail.status || '') }}
                </el-tag>
              </div>
            </el-col>
            <!-- 右侧信息 -->
            <el-col :span="12">
              <!-- 创建时间 -->
              <div class="detail-item">
                <label>创建时间:</label>
                <span>{{ formatDate(selectedRoleDetail.createdAt) }}</span>
              </div>
              <!-- 更新时间 -->
              <div class="detail-item">
                <label>更新时间:</label>
                <span>{{ formatDate(selectedRoleDetail.updatedAt) }}</span>
              </div>
            </el-col>
          </el-row>
        </div>
      </div>
    </el-dialog>

    <!-- 权限分配对话框（新版） -->
    <el-dialog v-model="showPermissionDialog" title="分配权限" width="900px">
      <div class="assign-header">
        <div class="role-info">
          <span class="role-name">角色：{{ currentRole.roleName }}</span>
          <span class="role-desc">描述：{{ currentRole.roleDescription || '无' }}</span>
        </div>
        <span class="selected-count">
          当前分类：{{ getCurrentCategorySelectedCount() }} 个 | 
          已选择：{{ selectedPermissions.length }} 个 | 
          总计：{{ permissionSearchKeyword ? filteredPermissionList.length + ' / ' + allPermissionsFlat.length : allPermissionsFlat.length }} 个权限
        </span>
      </div>
      <el-divider />
      <div class="assign-body">
        <!-- 左侧分组 -->
        <div class="category-list">
          <el-menu :default-active="selectedCategoryId" @select="handleCategorySelect">
            <el-menu-item
              v-for="cat in permissionCategories"
              :key="cat.id"
              :index="cat.id"
            >
              {{ cat.name }}
              <el-tag size="small" style="margin-left:8px;">{{ getCategoryCount(cat.id) }}</el-tag>
            </el-menu-item>
          </el-menu>
        </div>
        <!-- 右侧卡片 -->
        <div class="permission-list">
          <div class="permission-list-header">
            <span>{{ currentCategoryName }}</span>
            <div style="display:flex; align-items:center; gap:8px;">
              <el-input
                v-model="permissionSearchKeyword"
                size="small"
                clearable
                placeholder="搜索权限（名称/描述/代码）"
                style="width:260px;"
              >
                <template #prefix>
                  <el-icon><Search /></el-icon>
                </template>
              </el-input>
              <el-button-group>
                <el-button size="small" @click="selectAll">全选</el-button>
                <el-button size="small" @click="clearAll">清空</el-button>
              </el-button-group>
            </div>
          </div>
          <el-checkbox-group v-model="selectedPermissions">
            <div
              v-for="perm in filteredPermissionList"
              :key="perm.id"
              class="permission-item"
            >
              <el-checkbox :label="perm.id">
                <div>
                  <span class="perm-name">{{ perm.name }}</span>
                  <span class="perm-desc">{{ perm.description }}</span>
                </div>
              </el-checkbox>
            </div>
          </el-checkbox-group>
        </div>
      </div>
      <template #footer>
        <span class="dialog-footer">
          <el-button @click="showPermissionDialog = false">取消</el-button>
          <el-button type="primary" @click="savePermissions" :loading="savingPermissions">确定</el-button>
        </span>
      </template>
    </el-dialog>
  </div>
</template>

<script setup>
import { ref, reactive, computed, onMounted, onUnmounted } from 'vue'
import { 
  getRoleList, 
  addRole, 
  updateRole, 
  deleteRole, 
  enableRole, 
  disableRole,
  getRoleDetail,
  getRolePermissions,
  assignRolePermissions,
  getPermissions 
} from '@/api/role'
import { getAllPermissions } from '@/api/permission'
import { ElMessage, ElMessageBox } from 'element-plus'
import {
  Plus, Search, View, Edit, Delete, Message, Document, Setting, Check, Close, Refresh
} from '@element-plus/icons-vue'

// ==================== 响应式数据定义 ====================

// 加载状态控制
const loading = ref(false)
const addingRole = ref(false)
const savingPermissions = ref(false)

// 对话框显示状态控制
const showAddDialog = ref(false)           // 添加角色对话框
const showDetailDialog = ref(false)        // 角色详情对话框
const showPermissionDialog = ref(false)    // 权限管理对话框

// 角色详情数据
const selectedRoleDetail = ref({
  id: '',
  roleName: '',
  roleDescription: '',
  status: '',
  permissionCount: 0,
  createdAt: '',
  updatedAt: ''
})

// 当前编辑的角色
const currentRole = ref({})

// 权限分组数据
const permissionCategories = ref([]) // [{id, name}]
const permissionMap = ref({}) // { categoryId: [permission, ...] }
const selectedCategoryId = ref('')
const selectedPermissions = ref([])
const permissionSearchKeyword = ref('')
const allPermissionsFlat = ref([]) // 扁平化后的全部权限

// 当前分类名称
const currentCategoryName = computed(() => {
  const cat = permissionCategories.value.find(c => c.id === selectedCategoryId.value)
  return cat ? cat.name : ''
})

// 过滤后的权限列表：当有搜索关键词时，跨分类展示所有匹配项；否则仅展示当前分类
const filteredPermissionList = computed(() => {
  const keyword = permissionSearchKeyword.value.trim().toLowerCase()
  if (!keyword) {
    return permissionMap.value[selectedCategoryId.value] || []
  }
  // 合并所有分类后过滤
  const allPerms = allPermissionsFlat.value.length ? allPermissionsFlat.value : Object.values(permissionMap.value).flat()
  return allPerms.filter(p =>
    (p.name && p.name.toLowerCase().includes(keyword)) ||
    (p.description && p.description.toLowerCase().includes(keyword)) ||
    (p.code && p.code.toLowerCase().includes(keyword))
  )
})

// 分类计数（当有搜索词时，显示该分类下匹配的数量；否则显示该分类总数）
const getCategoryCount = (catId) => {
  const keyword = permissionSearchKeyword.value.trim()
  if (!keyword) return (permissionMap.value[catId] || []).length
  const list = filteredPermissionList.value
  const idsInCat = new Set((permissionMap.value[catId] || []).map(p => p.id))
  return list.filter(p => idsInCat.has(p.id)).length
}

// 分页相关数据
const pageSize = ref(10)                   // 每页显示条数

// 搜索和过滤相关数据
const searchKeyword = ref('')              // 搜索关键词
const statusFilter = ref('')               // 状态过滤条件

// 行内编辑相关数据
const editingRowId = ref(null)             // 当前正在编辑的行ID
// 备份原始行数据，用于取消编辑时恢复
let backupRow = null

// 角色数据列表
const roles = ref([])
const total = ref(0)
const currentPage = ref(1)

// 表单引用
const roleFormRef = ref(null)

// 搜索防抖定时器
let searchTimer = null

// 添加角色表单数据
const roleForm = reactive({
  roleName: '',
  roleDescription: '',
})

// 表单验证规则
const roleRules = {
  roleName: [
    { required: true, message: '请输入角色名称', trigger: 'blur' },
    { min: 2, max: 20, message: '角色名称长度在 2 到 20 个字符', trigger: 'blur' }
  ],
  roleDescription: [
    { max: 200, message: '角色描述不能超过 200 个字符', trigger: 'blur' }
  ]
}

// ==================== 计算属性 ====================

/**
 * 过滤后的角色列表
 * 根据搜索关键词和状态过滤条件过滤角色数据
 */
const filteredRoles = computed(() => {
  let filtered = roles.value

  // 根据搜索关键词过滤
  if (searchKeyword.value) {
    filtered = filtered.filter(role =>
      (role.roleName && role.roleName.toLowerCase().includes(searchKeyword.value.toLowerCase())) ||
      (role.roleDescription && role.roleDescription.toLowerCase().includes(searchKeyword.value.toLowerCase()))
    )
  }

  // 根据状态过滤
  if (statusFilter.value) {
    filtered = filtered.filter(role => role.status === statusFilter.value)
  }

  return filtered
})

// ==================== 工具函数 ====================

/**
 * 获取状态名称
 * @param {string} status - 状态标识
 * @returns {string} 状态显示名称
 */
const getStatusName = (status) => {
  if (!status) return '未知'
  const statusMap = {
    '0': '启用',
    '2': '禁用',
  }
  return statusMap[status] || status
}

/**
 * 获取状态类型（用于标签颜色）
 * @param {string} status - 状态标识
 * @returns {string} 状态标签类型
 */
const getStatusType = (status) => {
  const typeMap = {
    '0': 'success',
    '2': 'danger',
    'pending': 'warning'
  }
  return typeMap[status] || 'info'
}

/**
 * 获取角色颜色
 * @param {string} roleName - 角色名称
 * @returns {string} 角色头像背景色
 */
const getRoleColor = (roleName) => {
  if (!roleName) return '#409eff'
  const colors = ['#409eff', '#67c23a', '#e6a23c', '#f56c6c', '#909399']
  const index = roleName.charCodeAt(0) % colors.length
  return colors[index]
}



/**
 * 格式化日期
 * @param {string} dateStr - 日期字符串
 * @returns {string} 格式化后的日期
 */
const formatDate = (dateStr) => {
  if (!dateStr) return '未知'
  
  try {
    // 处理不同的日期格式
    let date
    if (typeof dateStr === 'string') {
      // 如果是ISO格式的字符串，直接创建Date对象
      if (dateStr.includes('T') || dateStr.includes('Z')) {
        date = new Date(dateStr)
      } else {
        // 处理其他格式的日期字符串
        date = new Date(dateStr.replace(/-/g, '/'))
      }
    } else if (dateStr instanceof Date) {
      date = dateStr
    } else {
      date = new Date(dateStr)
    }
    
    // 检查日期是否有效
    if (isNaN(date.getTime())) {
      return '未知'
    }
    
    // 格式化为中文日期时间
    return date.toLocaleString('zh-CN', {
      year: 'numeric',
      month: '2-digit',
      day: '2-digit',
      hour: '2-digit',
      minute: '2-digit',
      second: '2-digit'
    })
  } catch (e) {
    console.error('日期格式化错误:', e, '原始值:', dateStr)
    return '未知'
  }
}

// ==================== 数据加载函数 ====================

/**
 * 加载角色列表数据
 * 从后端API获取角色数据并更新本地状态
 */
const loadRoles = async () => {
  loading.value = true
  try {
    const res = await getRoleList()
    console.log(res);
    
    if (res.code === 200 && res.data) {
      // 数据格式转换
      const roleData = res.data.roles || res.data
      if (Array.isArray(roleData)) {
        roles.value = roleData.map(r => ({
          id: r.id,
          roleName: r.roleName || r.name,
          roleDescription: r.roleDescription || r.description,
          status: r.status === 0 ? '0' : (r.status === 2 ? '2' : '0'),
          permissionCount: r.permissionCount || 0,
          createdAt: r.createdAt,
          updatedAt: r.updatedAt
        }))
        total.value = res.data.total || roles.value.length
      } else {
        roles.value = []
        total.value = 0
      }
    } else {
      roles.value = []
      total.value = 0
      if (res.message) {
        ElMessage.warning(res.message)
      }
    }
  } catch (e) {
    console.error('加载角色列表失败:', e)
    roles.value = []
    total.value = 0
    ElMessage.error('加载角色列表失败，请检查网络连接')
  }
  loading.value = false
}

// ==================== 事件处理函数 ====================

/**
 * 处理搜索输入（防抖）
 */
const handleSearch = () => {
  if (searchTimer) {
    clearTimeout(searchTimer)
  }
  searchTimer = setTimeout(() => {
    currentPage.value = 1
    loadRoles()
  }, 500)
}

/**
 * 重置搜索和过滤条件
 */
const resetFilters = () => {
  searchKeyword.value = ''
  statusFilter.value = ''
  currentPage.value = 1
  loadRoles()
}

/**
 * 切换角色状态
 * @param {Object} role - 角色对象
 */
const toggleRoleStatus = (role) => {
  // 切换状态：0 -> 2, 2 -> 0
  role.status = role.status === '0' ? '2' : '0'
}

/**
 * 查看角色详情
 * @param {Object} role - 角色对象
 */
const viewRole = async (role) => {
  try {
    const res = await getRoleDetail()
    if (res.code === 200 && res.data) {
      selectedRoleDetail.value = {
        id: res.data.id,
        roleName: res.data.roleName || res.data.name,
        roleDescription: res.data.roleDescription || res.data.description,
        status: res.data.status === 0 ? '0' : '2',
        permissionCount: res.data.permissionCount || 0,
        createdAt: res.data.createdAt,
        updatedAt: res.data.updatedAt
      }
    } else {
      selectedRoleDetail.value = { ...role }
    }
    showDetailDialog.value = true
  } catch (e) {
    console.error('获取角色详情失败:', e)
    selectedRoleDetail.value = { ...role }
    showDetailDialog.value = true
  }
}

/**
 * 打开编辑模式
 * @param {number} id - 要编辑的角色ID
 */
const openEdit = (id) => {
  editingRowId.value = id
  // 查找对应的行数据并备份
  const row = roles.value.find(item => item.id === id)
  backupRow = { ...row }
}

/**
 * 保存编辑内容
 * @param {number} id - 要保存的角色ID
 */
const saveEdit = async (id) => {
  try {
    // 查找要编辑的角色
    const editRole = roles.value.find(item => item.id === id)
    const originalRole = backupRow
    
    // 调用API更新角色基本信息
    await updateRole(id, {
      roleName: editRole.roleName,
      roleDescription: editRole.roleDescription
    })
    
    // 如果状态发生变化，调用相应的启用/禁用函数
    if (editRole.status !== originalRole.status) {
      if (editRole.status === '0') {
        await enableRole(id)
      } else if (editRole.status === '2') {
        await disableRole(id)
      }
    }
    
    ElMessage.success('更新角色成功')
    editingRowId.value = null
    loadRoles()
  } catch (e) {
    console.error('更新角色失败:', e)
    ElMessage.error('更新失败')
  }
}

/**
 * 取消编辑
 * 恢复原始数据，退出编辑模式
 */
const cancelEdit = () => {
  if (editingRowId.value !== null && backupRow) {
    // 找到对应的行索引
    const idx = roles.value.findIndex(item => item.id === editingRowId.value)
    if (idx !== -1) {
      // 恢复原始数据
      Object.assign(roles.value[idx], backupRow)
    }
  }
  // 重置编辑状态
  editingRowId.value = null
  backupRow = null
}

/**
 * 删除角色
 * @param {Object} role - 要删除的角色对象
 */
const deleteRoleHandler = async (role) => {
  try {
    await ElMessageBox.confirm(`确定要删除角色 ${role.roleName} 吗？`, '确认删除', {
      confirmButtonText: '确定',
      cancelButtonText: '取消',
      type: 'warning'
    })
    
    await deleteRole(role.id)
    ElMessage.success('删除成功')
    loadRoles()
  } catch (e) {
    if (e !== 'cancel') {
      ElMessage.error('删除失败')
    }
  }
}

/**
 * 管理权限
 * @param {Object} role - 角色对象
 */
const managePermissions = async (role) => {
  currentRole.value = role
  showPermissionDialog.value = true

  try {

let {data}=await getPermissions()
console.log(data);


    // 1. 获取全部权限
    const allPermRes = await getPermissions()
    console.log(allPermRes);
    
    const allPermissions = allPermRes.data.permissions || []

    // 2. 获取当前角色已分配权限
    const rolePermRes = await getRolePermissions(role.id)
    console.log(rolePermRes);
    
    // 兼容两种结构
    let assigned = []
    if (rolePermRes.data.assignedPermissions) {
      assigned = rolePermRes.data.assignedPermissions
    } else if (Array.isArray(rolePermRes.data.permissions)) {
      // 如果返回的是权限对象数组
      assigned = rolePermRes.data.permissions.map(p => p.id)
    }

    // 3. 分组全部权限
    const categoryMap = {}
  const flatList = []
  allPermissions.forEach(perm => {
      const prefix = perm.permissionCode.split('.')[0]
      if (!categoryMap[prefix]) categoryMap[prefix] = []
    const item = {
        id: perm.id,
        name: perm.permissionName,
        description: perm.permissionDescription,
        code: perm.permissionCode
    }
    categoryMap[prefix].push(item)
    flatList.push(item)
    })
  // 构造分类列表，加入“全部权限”
  const cats = Object.keys(categoryMap).map(prefix => ({
      id: prefix,
      name: getCategoryName(prefix)
    }))
      permissionMap.value = categoryMap
  // “全部权限”分类放在最前
      permissionMap.value['all'] = flatList
      allPermissionsFlat.value = flatList
     permissionCategories.value = [{ id: 'all', name: '全部权限' }, ...cats]
     selectedCategoryId.value = 'all'
    selectedPermissions.value = assigned
  } catch (e) {
    console.error('加载权限数据失败:', e)
    ElMessage.error('加载权限数据失败')
  }
}

/**
 * 获取分类显示名称
 * @param {string} prefix - 权限代码前缀
 * @returns {string} 分类名称
 */
const getCategoryName = (prefix) => {
  const nameMap = {
    'user': '用户管理',
    'role': '角色管理', 
    'permission': '权限管理',
    'document': '文档管理',
    'vector': '向量管理',
    'system': '系统管理',
    'qa': '问答管理',
    'knowledgebase': '知识库管理'
  }
  return nameMap[prefix] || prefix
}

/**
 * 获取当前分类已选择的权限数量
 * @returns {number} 当前分类已选择的权限数量
 */
const getCurrentCategorySelectedCount = () => {
  if (!selectedCategoryId.value || !permissionMap.value[selectedCategoryId.value]) {
    return 0
  }
  
  const currentCategoryPermissions = permissionMap.value[selectedCategoryId.value]
  const currentCategoryIds = currentCategoryPermissions.map(p => p.id)
  
  return selectedPermissions.value.filter(id => currentCategoryIds.includes(id)).length
}

/**
 * 分类切换
 * @param {string} catId - 分类ID
 */
const handleCategorySelect = (catId) => {
  selectedCategoryId.value = catId
}

/**
 * 全选当前分类
 */
const selectAll = () => {
  const ids = filteredPermissionList.value.map(p => p.id)
  selectedPermissions.value = Array.from(new Set([...selectedPermissions.value, ...ids]))
}

/**
 * 清空当前分类
 */
const clearAll = () => {
  const ids = filteredPermissionList.value.map(p => p.id)
  selectedPermissions.value = selectedPermissions.value.filter(id => !ids.includes(id))
}

/**
 * 保存权限
 */
const savePermissions = async () => {
  savingPermissions.value = true
  try {
    await assignRolePermissions(currentRole.value.id, selectedPermissions.value)
    ElMessage.success('权限保存成功')
    showPermissionDialog.value = false
    loadRoles() // 刷新角色列表以更新权限数量
  } catch (e) {
    console.error('保存权限失败:', e)
    ElMessage.error('保存权限失败')
  } finally {
    savingPermissions.value = false
  }
}

/**
 * 添加角色
 * 验证表单数据，调用API添加角色，成功后刷新列表
 */
const addRoleHandler = async () => {
  if (!roleFormRef.value) {
    return
  }
  
  addingRole.value = true
  
  try {
    await roleFormRef.value.validate()
    
    const roleData = {
      roleName: roleForm.roleName,
      roleDescription: roleForm.roleDescription
    }
    
    const result = await addRole(roleData)
    
    ElMessage.success('添加角色成功')
    showAddDialog.value = false
    
    // 重置表单
    Object.assign(roleForm, {
      roleName: '',
      roleDescription: ''
    })
    
    // 刷新角色列表
    await loadRoles()
    
  } catch (e) {
    if (e !== false) { // 表单验证失败时 e 为 false
      ElMessage.error(`添加角色失败: ${e.message || e}`)
    }
  } finally {
    addingRole.value = false
  }
}

// ==================== 分页处理函数 ====================

/**
 * 处理每页显示条数变化
 * @param {number} val - 新的每页条数
 */
const handleSizeChange = (val) => {
  pageSize.value = val
  currentPage.value = 1
  loadRoles()
}

/**
 * 处理当前页码变化
 * @param {number} val - 新的页码
 */
const handleCurrentChange = (val) => {
  currentPage.value = val
  loadRoles()
}

// ==================== 生命周期钩子 ====================

/**
 * 组件挂载时执行
 * 初始化获取角色列表数据
 */
onMounted(() => {
  loadRoles()
})

/**
 * 组件卸载时执行
 * 清理定时器
 */
onUnmounted(() => {
  if (searchTimer) {
    clearTimeout(searchTimer)
  }
})
</script>

<style scoped>
/* 角色管理主容器 */
.role-management {
  padding: 30px;
  min-height: calc(100vh - 120px);
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  position: relative;
  z-index: 1;
  width: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  box-sizing: border-box;
}

/* 角色列表卡片样式 */
.role-list-card {
  margin-bottom: 20px;
  background: rgba(255, 255, 255, 0.95);
  backdrop-filter: blur(10px);
  border-radius: 20px;
  box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1);
  border: 1px solid rgba(255, 255, 255, 0.2);
  overflow: hidden;
  transition: transform 0.3s ease, box-shadow 0.3s ease;
  width: 100%;
  max-width: 1400px;
  margin: 0 auto 20px auto;
  align-self: center;
}

.role-list-card:hover {
  transform: translateY(-5px);
  box-shadow: 0 25px 50px rgba(0, 0, 0, 0.15);
}

/* 卡片头部样式 */
.card-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 30px 40px; /* 增加左右内边距 */
  background: linear-gradient(135deg, #f8fafc 0%, #e2e8f0 100%);
  border-bottom: 1px solid rgba(226, 232, 240, 0.8);
  position: relative;
  width: 100%;
  min-height: 80px;
  overflow: visible;
  box-sizing: border-box; /* 确保padding不会影响总宽度 */
}

.card-header::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 3px;
  background: linear-gradient(90deg, #667eea, #764ba2);
}

/* 头部左侧按钮组 */
.header-left {
  display: flex;
  gap: 15px;
  flex-shrink: 0;
  min-width: 0;
  margin-left: 10px; /* 添加左边距 */
}

/* 头部右侧搜索和过滤区域 */
.header-right {
  display: flex;
  align-items: center;
  gap: 15px;
  flex-wrap: nowrap;
  min-width: 0;
  margin-right: 30px; /* 增加右边距 */
  transform: translateX(-40px); /* 整体向左移动40px */
  position: relative; /* 添加相对定位 */
  z-index: 1; /* 确保元素层级正确 */
}

/* 搜索输入框样式 */
.search-input {
  width: 220px; /* 稍微减小宽度 */
  flex-shrink: 0;
}

/* 状态选择器样式 */
.status-select {
  width: 110px; /* 稍微减小宽度 */
  flex-shrink: 0;
}

/* 重置按钮样式 */
.reset-button {
  flex-shrink: 0;
  white-space: nowrap;
  min-width: 80px; /* 确保按钮有最小宽度 */
  padding: 8px 16px; /* 调整内边距 */
}

/* 角色信息显示区域 */
.role-info {
  display: flex;
  align-items: center;
  gap: 12px;
  text-align: left;
}

/* 角色详情信息 */
.role-details {
  display: flex;
  flex-direction: column;
  text-align: left;
}

/* 角色名样式 */
.role-name {
  font-weight: 600;
  color: #2d3748;
  font-size: 16px;
  text-align: left;
}

/* 操作按钮组 */
.operation-buttons {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  flex-wrap: nowrap;
  min-width: 200px;
  padding: 4px;
}

/* 分页容器 */
.pagination-container {
  margin-top: 30px;
  display: flex;
  justify-content: center;
  align-items: center;
  padding: 30px;
  background: linear-gradient(135deg, #f8fafc 0%, #e2e8f0 100%);
  border-radius: 16px;
  margin: 30px auto;
  width: 100%;
  max-width: 1400px;
  align-self: center;
}

/* 角色详情样式 */
.role-detail {
  padding: 30px;
}

/* 确保卡片内容区域全宽 */
.role-list-card .el-card__body {
  padding: 0;
  width: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}

/* 表格居中样式 */
:deep(.el-table) {
  background: transparent;
  border-radius: 16px;
  overflow: hidden;
  box-shadow: 0 8px 25px rgba(0, 0, 0, 0.1);
  width: 100% !important;
  max-width: 100% !important;
  margin: 0 auto !important;
  table-layout: fixed;
  display: block !important;
}

/* 确保表格内容不被截断 */
:deep(.el-table__body-wrapper) {
  overflow-x: auto !important;
}

/* 表格内部包装器居中 */
:deep(.el-table__inner-wrapper) {
  width: 100% !important;
  margin: 0 auto !important;
}

:deep(.el-table__header-wrapper) {
  width: 100% !important;
  margin: 0 auto !important;
}

:deep(.el-table__body-wrapper) {
  width: 100% !important;
  margin: 0 auto !important;
}

/* 表格列对齐样式 */
:deep(.el-table .el-table__cell:first-child) {
  text-align: left;
}

:deep(.el-table .el-table__cell:nth-child(2)) {
  text-align: left;
}

:deep(.el-table .el-table__cell:nth-child(3)) {
  text-align: center;
}

:deep(.el-table .el-table__cell:nth-child(4)) {
  text-align: center;
}

:deep(.el-table .el-table__cell:nth-child(5)) {
  text-align: center;
}

:deep(.el-table .el-table__cell:last-child) {
  text-align: center;
  min-width: 280px;
  padding: 8px 12px;
}

/* 操作按钮样式优化 */
.operation-buttons .el-button {
  padding: 6px 10px;
  font-size: 12px;
  min-width: auto;
  white-space: nowrap;
  border-radius: 6px;
  transition: all 0.3s ease;
  margin: 0 2px;
}

.operation-buttons .el-button:hover {
  transform: translateY(-1px);
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
}

/* 表格头部对齐样式 */
:deep(.el-table .el-table__header th:first-child) {
  text-align: left;
}

:deep(.el-table .el-table__header th:nth-child(2)) {
  text-align: left;
}

:deep(.el-table .el-table__header th:nth-child(3)) {
  text-align: center;
}

:deep(.el-table .el-table__header th:nth-child(4)) {
  text-align: center;
}

:deep(.el-table .el-table__header th:nth-child(5)) {
  text-align: center;
}

:deep(.el-table .el-table__header th:last-child) {
  text-align: center;
}

/* 详情头部样式 */
.detail-header {
  display: flex;
  align-items: center;
  gap: 25px;
  margin-bottom: 30px;
  padding: 25px;
  background: linear-gradient(135deg, #f8fafc 0%, #e2e8f0 100%);
  border-radius: 16px;
  border: 1px solid rgba(226, 232, 240, 0.8);
}

/* 详情信息标题 */
.detail-info h3 {
  margin: 0 0 15px 0;
  color: #2d3748;
  font-size: 24px;
  font-weight: 600;
}

/* 详情元信息 */
.detail-meta {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

/* 元信息项 */
.meta-item {
  display: flex;
  align-items: center;
  gap: 8px;
  color: #4a5568;
  font-size: 14px;
  padding: 8px 12px;
  background: rgba(255, 255, 255, 0.7);
  border-radius: 8px;
  transition: all 0.3s ease;
}

.meta-item:hover {
  background: rgba(255, 255, 255, 0.9);
  transform: translateX(5px);
}

/* 详情内容区域 */
.detail-content {
  margin-top: 30px;
}

/* 详情项样式 */
.detail-item {
  display: flex;
  align-items: center;
  margin-bottom: 20px;
  padding: 15px 20px;
  background: rgba(255, 255, 255, 0.7);
  border-radius: 12px;
  border: 1px solid rgba(226, 232, 240, 0.6);
  transition: all 0.3s ease;
}

.detail-item:hover {
  background: rgba(255, 255, 255, 0.9);
  transform: translateX(5px);
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}

/* 详情项标签 */
.detail-item label {
  width: 120px;
  font-weight: 600;
  color: #4a5568;
}

/* 详情项内容 */
.detail-item span {
  color: #2d3748;
  font-weight: 500;
}

/* 对话框底部按钮区域 */
.dialog-footer {
  display: flex;
  justify-content: flex-end;
  gap: 15px;
  padding: 20px 30px;
  background: linear-gradient(135deg, #f8fafc 0%, #e2e8f0 100%);
  border-top: 1px solid rgba(226, 232, 240, 0.8);
}

/* 权限分配样式 */
.assign-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 20px;
  padding: 20px 25px;
  background: linear-gradient(135deg, #f8fafc 0%, #e2e8f0 100%);
  border-radius: 12px;
  border: 1px solid rgba(226, 232, 240, 0.8);
}

.role-info {
  display: flex;

}

.role-name {
  font-weight: 600;
  color: #2d3748;
  font-size: 18px;
}

.role-desc {
  color: #718096;
  font-size: 14px;
  margin-top: 6px;
}

.selected-count {
  color: #667eea;
  font-weight: 600;
  font-size: 14px;
  background: linear-gradient(135deg, #e6fffa 0%, #b2f5ea 100%);
  padding: 10px 16px;
  border-radius: 8px;
  border: 1px solid #81e6d9;
  box-shadow: 0 2px 8px rgba(102, 126, 234, 0.1);
  white-space: nowrap;
  display: inline-block;
}

.assign-body {
  display: flex;
  min-height: 400px;
  background: rgba(255, 255, 255, 0.7);
  border-radius: 16px;
  overflow: hidden;
  border: 1px solid rgba(226, 232, 240, 0.8);
}

.category-list {
  width: 180px;
  border-right: 1px solid rgba(226, 232, 240, 0.8);
  padding: 20px;
  background: linear-gradient(135deg, #f8fafc 0%, #e2e8f0 100%);
}

.permission-list {
  flex: 1;
  padding: 25px;
  max-height: 60vh;
  overflow-y: auto;
  background: rgba(255, 255, 255, 0.9);
}

.permission-list-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 20px;
  padding-bottom: 15px;
  border-bottom: 2px solid rgba(226, 232, 240, 0.8);
  font-weight: 600;
  color: #2d3748;
  font-size: 16px;
}

.permission-item {
  background: linear-gradient(135deg, #f7fafc 0%, #edf2f7 100%);
  border-radius: 12px;
  margin-bottom: 15px;
  padding: 16px 20px;
  border: 1px solid rgba(226, 232, 240, 0.8);
  transition: all 0.3s ease;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
}

.permission-item:hover {
  background: linear-gradient(135deg, #e6fffa 0%, #b2f5ea 100%);
  border-color: #667eea;
  transform: translateX(5px);
  box-shadow: 0 4px 12px rgba(102, 126, 234, 0.15);
}

/* 自定义滚动条（权限列表区域） */
.permission-list::-webkit-scrollbar { 
  width: 10px; 
}
.permission-list::-webkit-scrollbar-track { 
  background: rgba(245, 247, 250, 0.8); 
  border-radius: 8px; 
}
.permission-list::-webkit-scrollbar-thumb { 
  background: linear-gradient(135deg, #cbd5e0, #a0aec0); 
  border-radius: 8px; 
  border: 2px solid rgba(245, 247, 250, 0.8);
}
.permission-list::-webkit-scrollbar-thumb:hover { 
  background: linear-gradient(135deg, #a0aec0, #718096); 
}

.perm-name {
  font-weight: 600;
  color: #2d3748;
  margin-right: 10px;
  font-size: 14px;
}

.perm-desc {
  color: #718096;
  font-size: 13px;
  display: block;
  margin-top: 6px;
  line-height: 1.4;
}

/* Element Plus 组件样式增强 */
:deep(.el-button) {
  border-radius: 12px;
  padding: 10px 20px;
  font-weight: 500;
  transition: all 0.3s ease;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
  border: none;
}

:deep(.el-button--primary) {
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  box-shadow: 0 4px 15px rgba(102, 126, 234, 0.3);
}

:deep(.el-button--primary:hover) {
  transform: translateY(-2px);
  box-shadow: 0 6px 20px rgba(102, 126, 234, 0.4);
}

:deep(.el-button--success) {
  background: linear-gradient(135deg, #48bb78 0%, #38a169 100%);
  box-shadow: 0 4px 15px rgba(72, 187, 120, 0.3);
}

:deep(.el-button--danger) {
  background: linear-gradient(135deg, #f56565 0%, #e53e3e 100%);
  box-shadow: 0 4px 15px rgba(245, 101, 101, 0.3);
}

:deep(.el-button--warning) {
  background: linear-gradient(135deg, #ed8936 0%, #dd6b20 100%);
  box-shadow: 0 4px 15px rgba(237, 137, 54, 0.3);
}

:deep(.el-button--info) {
  background: linear-gradient(135deg, #a0aec0 0%, #718096 100%);
  box-shadow: 0 4px 15px rgba(160, 174, 192, 0.3);
}

:deep(.el-button--text) {
  background: transparent;
  box-shadow: none;
  color: #667eea;
  font-weight: 500;
}

:deep(.el-button--text:hover) {
  background: rgba(102, 126, 234, 0.1);
  color: #5a67d8;
  transform: none;
}

:deep(.el-input__wrapper) {
  border-radius: 12px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
  border: 1px solid rgba(226, 232, 240, 0.8);
  transition: all 0.3s ease;
}

:deep(.el-input__wrapper:hover) {
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
  border-color: #667eea;
}

:deep(.el-input__wrapper.is-focus) {
  box-shadow: 0 4px 15px rgba(102, 126, 234, 0.2);
  border-color: #667eea;
}

:deep(.el-select) {
  border-radius: 12px;
}

:deep(.el-select .el-input__wrapper) {
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}

:deep(.el-table) {
  background: transparent;
  border-radius: 16px;
  overflow: hidden;
  box-shadow: 0 8px 25px rgba(0, 0, 0, 0.1);
  width: 100% !important;
  table-layout: auto;
}

:deep(.el-table__header) {
  background: linear-gradient(135deg, #f8fafc 0%, #e2e8f0 100%);
}

:deep(.el-table__header th) {
  background: transparent;
  color: #2d3748;
  font-weight: 600;
  border-bottom: 2px solid rgba(226, 232, 240, 0.8);
  padding: 16px 12px;
  text-align: left;
}

:deep(.el-table__body tr) {
  transition: all 0.3s ease;
}

:deep(.el-table__body tr:hover) {
  background: linear-gradient(135deg, #f7fafc 0%, #edf2f7 100%);
  transform: scale(1.01);
}

:deep(.el-table__body td) {
  padding: 16px 12px;
  border-bottom: 1px solid rgba(226, 232, 240, 0.6);
  text-align: left;
}

:deep(.el-table__body) {
  width: 100%;
}

:deep(.el-table__header-wrapper) {
  width: 100%;
}

:deep(.el-table__body-wrapper) {
  width: 100%;
}

:deep(.el-table__inner-wrapper) {
  width: 100%;
}

:deep(.el-table__cell) {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  text-align: left;
}

:deep(.el-table .cell) {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  text-align: left;
}

:deep(.el-table__fixed) {
  width: auto !important;
}

:deep(.el-table__fixed-right) {
  width: auto !important;
}

/* 自定义滚动条样式 */
:deep(.el-table__body-wrapper::-webkit-scrollbar) {
  height: 8px;
}

:deep(.el-table__body-wrapper::-webkit-scrollbar-track) {
  background: rgba(245, 247, 250, 0.8);
  border-radius: 4px;
}

:deep(.el-table__body-wrapper::-webkit-scrollbar-thumb) {
  background: linear-gradient(135deg, #cbd5e0, #a0aec0);
  border-radius: 4px;
}

:deep(.el-table__body-wrapper::-webkit-scrollbar-thumb:hover) {
  background: linear-gradient(135deg, #a0aec0, #718096);
}

:deep(.el-tag) {
  border-radius: 8px;
  padding: 6px 12px;
  font-weight: 500;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
  transition: all 0.3s ease;
}

:deep(.el-tag:hover) {
  transform: translateY(-1px);
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}

:deep(.el-tag--success) {
  background: linear-gradient(135deg, #48bb78 0%, #38a169 100%);
  border: none;
  color: white;
}

:deep(.el-tag--danger) {
  background: linear-gradient(135deg, #f56565 0%, #e53e3e 100%);
  border: none;
  color: white;
}

:deep(.el-tag--info) {
  background: linear-gradient(135deg, #a0aec0 0%, #718096 100%);
  border: none;
  color: white;
}

:deep(.el-dialog) {
  border-radius: 20px;
  overflow: hidden;
  box-shadow: 0 25px 50px rgba(0, 0, 0, 0.15);
}

:deep(.el-dialog__header) {
  background: linear-gradient(135deg, #f8fafc 0%, #e2e8f0 100%);
  padding: 25px 30px;
  border-bottom: 1px solid rgba(226, 232, 240, 0.8);
}

:deep(.el-dialog__title) {
  color: #2d3748;
  font-weight: 600;
  font-size: 18px;
}

:deep(.el-dialog__body) {
  padding: 30px;
  background: rgba(255, 255, 255, 0.95);
}

:deep(.el-form-item__label) {
  color: #4a5568;
  font-weight: 600;
}

:deep(.el-textarea__inner) {
  border-radius: 12px;
  border: 1px solid rgba(226, 232, 240, 0.8);
  transition: all 0.3s ease;
}

:deep(.el-textarea__inner:focus) {
  border-color: #667eea;
  box-shadow: 0 4px 15px rgba(102, 126, 234, 0.2);
}

:deep(.el-menu) {
  background: transparent;
  border: none;
}

:deep(.el-menu-item) {
  border-radius: 8px;
  margin-bottom: 8px;
  transition: all 0.3s ease;
  color: #4a5568;
  font-weight: 500;
}

:deep(.el-menu-item:hover) {
  background: linear-gradient(135deg, #e6fffa 0%, #b2f5ea 100%);
  color: #667eea;
  transform: translateX(5px);
}

:deep(.el-menu-item.is-active) {
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  color: white;
}

:deep(.el-checkbox) {
  margin-right: 0;
}

:deep(.el-checkbox__input.is-checked .el-checkbox__inner) {
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  border-color: #667eea;
}

:deep(.el-checkbox__inner:hover) {
  border-color: #667eea;
}

:deep(.el-pagination) {
  background: transparent;
}

:deep(.el-pagination .el-pager li) {
  border-radius: 8px;
  transition: all 0.3s ease;
  font-weight: 500;
}

:deep(.el-pagination .el-pager li.is-active) {
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  color: white;
  box-shadow: 0 4px 12px rgba(102, 126, 234, 0.3);
}

:deep(.el-pagination .el-pager li:hover) {
  background: rgba(102, 126, 234, 0.1);
  color: #667eea;
}

:deep(.el-pagination .btn-prev),
:deep(.el-pagination .btn-next) {
  border-radius: 8px;
  transition: all 0.3s ease;
}

:deep(.el-pagination .btn-prev:hover),
:deep(.el-pagination .btn-next:hover) {
  background: rgba(102, 126, 234, 0.1);
  color: #667eea;
}

/* 加载状态样式 */
:deep(.el-loading-mask) {
  background: rgba(255, 255, 255, 0.9);
  backdrop-filter: blur(5px);
  border-radius: 16px;
}

/* 响应式设计 */
@media (max-width: 768px) {
  .role-management {
    padding: 15px;
    align-items: center;
  }
  
  .role-list-card {
    max-width: 100%;
    margin: 0 auto 15px auto;
  }
  
  .table-wrapper {
    width: 100%;
    margin: 0 auto;
  }
  
  .centered-table {
    width: 100% !important;
    margin: 0 auto !important;
  }
  
  .pagination-container {
    max-width: 100%;
    margin: 15px auto;
  }
  
  .card-header {
    flex-direction: column;
    gap: 15px;
    align-items: stretch;
    min-height: auto;
    padding: 20px; /* 在小屏幕上减少内边距 */
  }
  
  .header-right {
    flex-wrap: wrap;
    gap: 10px;
    justify-content: center;
    transform: none; /* 在小屏幕上取消transform */
    margin-right: 0; /* 在小屏幕上取消右边距 */
  }
  
  .search-input,
  .status-select {
    width: 100%;
    max-width: 300px;
  }
  
  .reset-button {
    width: 100%;
    max-width: 200px;
  }
  
  .assign-body {
    flex-direction: column;
  }
  
  .category-list {
    width: 100%;
    border-right: none;
    border-bottom: 1px solid rgba(226, 232, 240, 0.8);
  }
  
  .permission-list {
    padding: 15px;
  }
  
  /* 小屏幕下操作按钮优化 */
  .operation-buttons {
    flex-wrap: wrap;
    gap: 4px;
    min-width: auto;
  }
  
  .operation-buttons .el-button {
    padding: 4px 8px;
    font-size: 11px;
  }
  
  /* 小屏幕下操作列宽度调整 */
  :deep(.el-table .el-table__cell:last-child) {
    min-width: 200px;
    padding: 4px 8px;
  }
  
  .permission-list-header {
    flex-direction: column;
    gap: 10px;
    align-items: stretch;
  }
}

/* 角色信息显示样式 */
.role-info {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 8px 0;
}

.role-details {
  display: flex;
  flex-direction: column;
  gap: 4px;
  flex: 1;
  min-width: 0;
}

.role-name-text {
  font-weight: 600;
  color: #2c3e50;
  font-size: 14px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 120px;
}

/* 角色头像样式 */
:deep(.el-avatar) {
  border: 2px solid #e1e8ed;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
  transition: all 0.3s ease;
}

:deep(.el-avatar:hover) {
  transform: scale(1.05);
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}

/* 确保表格完全居中的最终样式 */
.role-management {
  width: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-start;
  padding: 20px;
  box-sizing: border-box;
}

/* 角色列表卡片完全居中 */
.role-list-card {
  width: 100%;
  max-width: 1400px;
  margin: 0 auto 20px auto;
  align-self: center;
}

/* 表格包装器完全居中 */
.table-wrapper {
  width: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
  margin: 0 auto;
}

/* 专门的居中表格样式 */
.centered-table {
  width: 100% !important;
  max-width: 100% !important;
  margin: 0 auto !important;
  display: block !important;
}

/* 表格居中样式 */
:deep(.el-table) {
  width: 100% !important;
  max-width: 100% !important;
  margin: 0 auto !important;
  table-layout: fixed !important;
  display: block !important;
}

/* 表格内部包装器居中 */
:deep(.el-table__inner-wrapper) {
  width: 100% !important;
  margin: 0 auto !important;
}

:deep(.el-table__header-wrapper) {
  width: 100% !important;
  margin: 0 auto !important;
}

:deep(.el-table__body-wrapper) {
  width: 100% !important;
  margin: 0 auto !important;
}


</style> 